package com.aggregate.pay.weixin.support;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.TreeMap;
import java.util.Map.Entry;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.aggregate.pay.weixin.support.utils.MD5;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;

/**
 * 微信官方支付工具类
 * @author Moyq5
 * @date 2018年6月16日
 */
public class Tool {
	
	private static final Logger log = LoggerFactory.getLogger(Tool.class);

	public static <T> T sign(T data, String key) throws Exception {
		Map<String, Object> map = fillPropertiesToMap(data);
		map.remove("sign");// sign参数不参与签名
		
		StringBuffer sb = new StringBuffer();
		for (Entry<String, Object> entry: map.entrySet()) {
			sb.append(entry.getKey() + "=" + entry.getValue() + "&");
		}
		sb.append("key=" + key);

		log.debug("签名内容：{}", sb.toString());
		String sign = MD5.MD5Encode(sb.toString()).toUpperCase();
		log.debug("签名值：{}", sign);
		Method method = data.getClass().getMethod("setSign", String.class);
		method.setAccessible(true);
		method.invoke(data, sign);
		
		return data;
	}
	
	private static Map<String, Object> fillPropertiesToMap(Object data) throws Exception {
		Map<String, Object> map = new TreeMap<String, Object>();
		fillPropertiesToMap(data, data.getClass(), map);
		return map;
	}
	
	private static void fillPropertiesToMap(Object data, Class<?> clazz, Map<String, Object> map) throws Exception {
		Field[] fields = clazz.getDeclaredFields();
		for (Field field: fields) {
			Method method = data.getClass().getMethod("get" + field.getName().substring(0, 1).toUpperCase() + field.getName().substring(1));
			method.setAccessible(true);
			Object value = method.invoke(data);
			if (null != value && !String.valueOf(value).isEmpty()) {
				String propertyName = field.getName();
				JacksonXmlProperty jxp = field.getAnnotation(JacksonXmlProperty.class);
				if (null != jxp) {
					propertyName = jxp.localName();
				}
				map.put(propertyName, value);
			}
		}
		Class<?> superClazz = clazz.getSuperclass();
		if (null != superClazz) {
			fillPropertiesToMap(data, superClazz, map);
		}
	}
	
}
